package com.xdj.iot.util.excelUtils;

import com.xdj.iot.util.excelUtils.processor.ExcelProcessor;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.Font;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;

/**
 * created by chongyahhh
 * 2020/2/21
 */
public class ExcelWorkBookCreator {
    private String excelFileName;
    private List<ExcelAssistBean> sheets;
    private HSSFWorkbook hssfWorkbook;
    private final String EXCEL_SHEET_PASSWORD = "123321";

    public ExcelWorkBookCreator(String excelFileName) {
        this.excelFileName = excelFileName;
        hssfWorkbook = new HSSFWorkbook();
        sheets = new ArrayList<>();
    }

    public void addOneSheet(String sheetName, List<?> data, Class targetClass){
        sheets.add(new ExcelAssistBean(hssfWorkbook,sheetName,data,targetClass));
    }

    public void addOneSheet(String sheetName, List<?> data, Class targetClass, boolean customMode){
        sheets.add(new ExcelAssistBean(hssfWorkbook,sheetName,data,targetClass,customMode));
    }

    public void addOneSheet(String sheetName, List<?> data, Class targetClass, ExcelProcessor excelProcessor){
        sheets.add(new ExcelAssistBean(hssfWorkbook,sheetName,data,targetClass,excelProcessor));
    }

    public void addOneSheet(String sheetName, List<?> data, Class targetClass, ExcelProcessor excelProcessor, boolean customMode){
        sheets.add(new ExcelAssistBean(hssfWorkbook,sheetName,data,targetClass,excelProcessor,customMode));
    }


    /**
     * 导出 excel
     * @param response
     * @return
     * @throws Exception
     */
    public void excelExport(HttpServletResponse response) throws Exception{
        //设置文件名
        response.setContentType("multipart/form-data");
        response.setHeader("Content-Disposition", "attachment;fileName="+ URLEncoder.encode((excelFileName + ".xls"),"UTF-8"));
        OutputStream os = response.getOutputStream();
        //开始注入数据
        for(int sheetIndex = 0;sheetIndex < sheets.size();sheetIndex++) {
            ExcelAssistBean currentSheetMsg = sheets.get(sheetIndex);
            HSSFSheet currentSheet = hssfWorkbook.createSheet(currentSheetMsg.getSheetName());
            currentSheet.protectSheet(EXCEL_SHEET_PASSWORD);
            ExcelProcessor excelProcessor = currentSheetMsg.getExcelProcessor();
            int firstRowNum = excelProcessor.customOperationBeforeInvokeData(currentSheetMsg,currentSheet);
            if(currentSheetMsg.isCustomMode()){
                invokeDataUnderCustomModel(currentSheetMsg,currentSheet,firstRowNum);
            } else {
                invokeData(currentSheetMsg,currentSheet,firstRowNum);
            }
            excelProcessor.customOperationAfterInvokeData(currentSheetMsg,currentSheet,firstRowNum);
        }
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        hssfWorkbook.write(outputStream);
        outputStream.flush();
        hssfWorkbook.close();
        outputStream.close();
        InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());

        int b = 0;
        byte[] buffer = new byte[512];
        while (b != -1){
            b = inputStream.read(buffer);
            if(b != -1){
                os.write(buffer,0,b);
            }

        }
        if(inputStream != null){
            inputStream.close();
        }
        if(os!=null){
            os.close();
            os.flush();
        }
    }

    /**
     * 不开启自定义文本模式下注入正文
     * @param currentSheet
     * @param hssfSheet
     * @param firstRowNum
     * @throws Exception
     */
    private void invokeData(ExcelAssistBean currentSheet,HSSFSheet hssfSheet,int firstRowNum) throws Exception{
        //设置表头
        HSSFRow firstRow = hssfSheet.createRow(firstRowNum);
        HSSFCellStyle cellStyle = hssfWorkbook.createCellStyle();
        Font titleFont = hssfWorkbook.createFont();
        //加粗标题字体
        titleFont.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
        cellStyle.setFont(titleFont);
        cellStyle.setLocked(true);
        HSSFCell titleCell;
        for(int titleIndex = 0;titleIndex < currentSheet.getOrderedTitles().size();titleIndex++){
            titleCell = firstRow.createCell(titleIndex);
            titleCell.setCellValue(currentSheet.getOrderedTitles().get(titleIndex));
            titleCell.setCellStyle(cellStyle);
        }
        //注入数据
        List<?> currentData = currentSheet.getData();
        List<Field> fields = currentSheet.getOrderedFields();
        cellStyle = hssfWorkbook.createCellStyle();
        cellStyle.setLocked(true);
        HSSFRow currentRow;
        for(int rowIndex = 0;rowIndex < currentData.size();rowIndex++){
            currentRow = hssfSheet.createRow(rowIndex + firstRowNum + 1);
            HSSFCell currentCell;
            Object obj = currentData.get(rowIndex);
            for(int cellIndex = 0;cellIndex < fields.size();cellIndex++){
                currentCell = currentRow.createCell(cellIndex);
                currentCell.setCellStyle(cellStyle);
                if(!fields.get(cellIndex).isAccessible()){
                    fields.get(cellIndex).setAccessible(true);
                    if(fields.get(cellIndex).get(obj) != null){
                        currentCell.setCellValue(fields.get(cellIndex).get(obj).toString());
                    }
                    fields.get(cellIndex).setAccessible(false);
                } else {
                    if(fields.get(cellIndex).get(obj) != null){
                        currentCell.setCellValue(fields.get(cellIndex).get(obj).toString());
                    }
                }
            }
        }
    }

    /**
     * 开启自定义文本模式下注入正文
     * @param currentSheet
     * @param hssfSheet
     * @param firstRowNum
     * @throws Exception
     */
    private void invokeDataUnderCustomModel(ExcelAssistBean currentSheet,HSSFSheet hssfSheet,int firstRowNum) throws Exception{
        //设置表头
        HSSFRow firstRow = hssfSheet.createRow(firstRowNum);
        currentSheet.titleCellStyleInvoke(firstRow);
        //注入数据
        currentSheet.contentCellStyleInvoke(hssfSheet,firstRowNum);
    }

    public String getExcelFileName() {
        return excelFileName;
    }

    public void setExcelFileName(String excelFileName) {
        this.excelFileName = excelFileName;
    }

    public List<ExcelAssistBean> getSheets() {
        return sheets;
    }

    public void setSheets(List<ExcelAssistBean> sheets) {
        this.sheets = sheets;
    }
}
